package grpcclient

import (
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"time"
	"wmicro/client/grpcclient/interceptors"
)

type GrpcClient struct {
	target                   string                         // 地址 “192.168.0.1:8090”
	timeout                  time.Duration                  // 超时时间
	unaryClientInterceptors  []grpc.UnaryClientInterceptor  // 拦截器
	streamClientInterceptors []grpc.StreamClientInterceptor // 流拦截器
	dialOptions              []grpc.DialOption              // grpc 客户端连接选项
	balancerName             string                         // 负债均衡策略
	insecure                 bool                           // 是否使用不安全的连接
}

type GrpcClientOption func(c *GrpcClient)

func WithGrpcClientOptionTarget(target string) GrpcClientOption {
	return func(c *GrpcClient) {
		c.target = target
	}
}

func WithGrpcClientOptionTimeout(timeout time.Duration) GrpcClientOption {
	return func(c *GrpcClient) {
		c.timeout = timeout
	}
}

func WithGrpcClientOptionUnaryClientInterceptors(unaryClientInterceptors []grpc.UnaryClientInterceptor) GrpcClientOption {
	return func(c *GrpcClient) {
		c.unaryClientInterceptors = unaryClientInterceptors
	}
}

func WithGrpcClientOptionStreamClientInterceptors(streamClientInterceptors []grpc.StreamClientInterceptor) GrpcClientOption {
	return func(c *GrpcClient) {
		c.streamClientInterceptors = streamClientInterceptors
	}
}

func WithGrpcClientOptionDialOption(dialOptions []grpc.DialOption) GrpcClientOption {
	return func(c *GrpcClient) {
		c.dialOptions = dialOptions
	}
}

func WithGrpcClientOptionBalancerName(balancerName string) GrpcClientOption {
	return func(c *GrpcClient) {
		c.balancerName = balancerName
	}
}

func WithGrpcClientOptionInsecure(insecure bool) GrpcClientOption {
	return func(c *GrpcClient) {
		c.insecure = insecure
	}
}

func New(ctx context.Context, opts ...GrpcClientOption) (*grpc.ClientConn, error) {
	c := &GrpcClient{
		timeout:                  5 * time.Second,
		balancerName:             "round_robin",
		insecure:                 true, // 默认使用不安全传输
		unaryClientInterceptors:  make([]grpc.UnaryClientInterceptor, 0),
		streamClientInterceptors: make([]grpc.StreamClientInterceptor, 0),
		dialOptions:              make([]grpc.DialOption, 0),
	}

	for _, o := range opts {
		o(c)
	}

	// https://juejin.cn/post/7229145941399027771
	// https://juejin.cn/post/7165464909730299934

	var dialOptions = []grpc.DialOption{
		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingPolicy": "%s"}`, c.balancerName)), // 设置轮询算法
		//grpc.WithTransportCredentials(insecure.NewCredentials()),
		//grpc.WithChainUnaryInterceptor(c.unaryClientInterceptors...),
		//grpc.WithChainStreamInterceptor(c.streamClientInterceptors...),
	}
	if c.insecure {
		dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
	}
	// 客户端拦截器
	c.unaryClientInterceptors = append(c.unaryClientInterceptors, interceptors.UnaryTimeoutInterceptor(c.timeout)) // 添加超时拦截器
	if len(c.unaryClientInterceptors) > 0 {
		dialOptions = append(dialOptions, grpc.WithChainUnaryInterceptor(c.unaryClientInterceptors...))
	}
	// 流客户端拦截器
	if len(c.streamClientInterceptors) > 0 {
		dialOptions = append(dialOptions, grpc.WithChainStreamInterceptor(c.streamClientInterceptors...))
	}

	// dialOptions
	dialOptions = append(dialOptions, c.dialOptions...)

	//defer conn.Close()

	// 服务发现
	// 1.直连模式 grpc客户端 -> 一个服务连接信息 -> 连接一个grpc服务。只能一对一连接
	// 2.服务发现模式 grpc客户端 -> 服务注册中心获取一组服务连接信息 -> 通过轮询算法 -> 间接实现一对多连接

	return grpc.DialContext(context.Background(), c.target, dialOptions...)
}
